package com.zt.student.config;

import com.zt.common.common.MultiRealmAuthenticator;
import com.zt.common.pojo.common.MyCredentialsMatcher;
import com.zt.student.filter.JwtFilter;
import com.zt.student.shiro.JwtRealm;
import com.zt.student.shiro.PwdRealm;
import com.zt.student.shiro.WechatRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.AuthenticationStrategy;
import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SessionStorageEvaluator;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import javax.servlet.Filter;
import java.util.*;

/**
 * description:
 * author:zt
 * date:2021-10-23
 */
@Configuration
public class ShiroConfig {

    /**
     * 由Spring管理 Shiro的生命周期
     */
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 开启对 Shiro 注解的支持
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        // 强制使用cglib，防止重复代理和可能引起代理出错的问题
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    //不向 Spring容器中注册 JwtFilter Bean，防止 Spring 将 JwtFilter 注册为全局过滤器
    @Bean
    public FilterRegistrationBean<Filter> registration(JwtFilter filter) {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<Filter>(filter);
        registration.setEnabled(false);
        return registration;
    }


    //创建ShiroFilter（用于拦截所有请求，对受限资源进行Shiro的认证和授权判断）
    //Shiro提供了丰富的过滤器（anon等），不过在这里就需要加入我们自定义的JwtFilter了
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

        // 添加自己的过滤器并且取名为jwt
        Map<String, Filter> filterMap = new HashMap<>();
        filterMap.put("jwt", new JwtFilter());
        shiroFilterFactoryBean.setFilters(filterMap);

        //配置系统的受限资源以及对应的过滤器
//        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized/无权限");
        Map<String, String> ruleMap = new LinkedHashMap<>();

        //登录 与 返回错误信息 不受限
        ruleMap.put("/student/login", "anon");
        ruleMap.put("/student/update", "anon");

        ruleMap.put("/activeClass/**", "jwt");
        ruleMap.put("/classSelection/**", "jwt");
        ruleMap.put("/exam/**", "jwt");
        ruleMap.put("/homeworkAnswer/**", "jwt");
        ruleMap.put("/homework/**", "jwt");
        ruleMap.put("/originStudent/**", "jwt");
        ruleMap.put("/privateLetter/**", "jwt");
        ruleMap.put("/student/**", "jwt");

//        ruleMap.put("/exception/**", "anon");
//        ruleMap.put("/favicon.ico", "anon");


//        ruleMap.put("/**", "jwt");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(ruleMap);
        return shiroFilterFactoryBean;
    }

    /**
     * 禁用session, 不保存用户登录状态。保证每次请求都重新认证
     */
    @Bean
    protected SessionStorageEvaluator sessionStorageEvaluator() {
        DefaultSessionStorageEvaluator sessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        sessionStorageEvaluator.setSessionStorageEnabled(false);
        return sessionStorageEvaluator;
    }

    @Bean
    public ModularRealmAuthenticator authenticator() {
        ModularRealmAuthenticator authenticator = new MultiRealmAuthenticator();
//         设置多 Realm的认证策略，默认 AtLeastOneSuccessfulStrategy
        AuthenticationStrategy strategy = new FirstSuccessfulStrategy();
        authenticator.setAuthenticationStrategy(strategy);
        authenticator.setRealms(Arrays.asList(wechatRealm(),jwtRealm(),pwdRealm()));
//        ModularRealmAuthenticator authenticator = new CustomModularRealmAuthenticator();
        return authenticator;
    }

    //创建安全管理器
    @Bean("securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        //设置ModularRealmAuthenticator
        List<Realm> realms = new ArrayList<>();
        securityManager.setAuthenticator(authenticator());
        //给安全管理器设置realm
        realms.add(jwtRealm());
        realms.add(wechatRealm());
        realms.add(pwdRealm());
        securityManager.setRealms(realms);

        //关闭shiro的session（无状态的方式使用shiro）
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);

        return securityManager;
    }


    @Bean
    public JwtRealm jwtRealm(){
        JwtRealm jwtRealm = new JwtRealm();
        //将加密算法设置为自定义匹配器
        jwtRealm.setCredentialsMatcher(new MyCredentialsMatcher());
        return jwtRealm;
    }

    @Bean
    public WechatRealm wechatRealm(){
        WechatRealm wechatRealm = new WechatRealm();
        //将加密算法设置为自定义匹配器
        wechatRealm.setCredentialsMatcher(new MyCredentialsMatcher());
        return wechatRealm;
    }

    @Bean
    public PwdRealm pwdRealm(){
        PwdRealm pwdRealm = new PwdRealm();

        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        hashedCredentialsMatcher.setHashIterations(1024);

        pwdRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        return pwdRealm;
    }

}
